﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;

namespace GestorDeFlotas.Core
{
    public class Rol
    {
        public int Id { get; set; }
        
        public string Nombre { get; set; }

        public bool Activo { get; set; }

        public List<int> Funcionalidades { get; private set; }

        public Rol()
        {
            this.Funcionalidades = new List<int>();
        }

        public Rol(int id)
            : this()
        {
            this.Id = id;
        }


        public Rol Cargar()
        {
            CargarDatosRol();
            CargarFuncionalidades();

            return this;
        }

        public void Crear()
        {
            using (SqlConnection connection = SqlUtils.GetConnection())
            {
                connection.Open();
                SqlTransaction transaction = connection.BeginTransaction();

                try
                {
                    CrearRol(connection, transaction);
                    AgregarFuncionalidades(connection, transaction);
                    transaction.Commit();
                }
                catch (Exception)
                {
                    transaction.Rollback();
                    throw;
                }
            }
        }

        public void Modificar()
        {
            using (SqlConnection connection = SqlUtils.GetConnection())
            {
                connection.Open();
                SqlTransaction transaction = connection.BeginTransaction();

                try
                {
                    ModificarDatosRol(connection, transaction);
                    ModificarFuncionalidades(connection, transaction);
                    transaction.Commit();
                }
                catch (Exception)
                {
                    transaction.Rollback();
                    throw;
                }
            }
        }

        public void SetInactivo()
        {
            using (SqlConnection connection = SqlUtils.GetConnection())
            {
                string sql = "UPDATE [CRAZY_TAXI].[TL_Roles] SET rol_activo = 0 WHERE rol_codigo = @RolID";

                // Codigo para borrar el rol de la base
                SqlCommand updateRecord = SqlUtils.GetNewCommand(sql);

                SqlParameter rowParameter = new SqlParameter("@RolID", SqlDbType.Int);
                rowParameter.IsNullable = false;
                rowParameter.Value = this.Id;

                updateRecord.Parameters.Add(rowParameter);
                updateRecord.Connection = connection;
                updateRecord.Connection.Open();
                updateRecord.ExecuteNonQuery();
            }            
        }

        private void AgregarFuncionalidades(SqlConnection connection, SqlTransaction transaction)
        {
            if (this.Funcionalidades.Count > 0)
            {
                StringBuilder sql = new StringBuilder();
                sql.AppendFormat("INSERT INTO [CRAZY_TAXI].[TL_FuncionalidadesPorRol]");

                foreach (int func in this.Funcionalidades)
                {
                    sql.AppendFormat(" SELECT {0}, {1} UNION ALL", func, this.Id);
                }

                sql.Remove(sql.ToString().LastIndexOf(" UNION ALL"), " UNION ALL".Length);

                SqlCommand agregarFuncionalidades = SqlUtils.GetNewCommand(sql.ToString());
                agregarFuncionalidades.Connection = connection;
                agregarFuncionalidades.Transaction = transaction;
                agregarFuncionalidades.ExecuteNonQuery();
            }            
        }

        private void CrearRol(SqlConnection connection, SqlTransaction transaction)
        {
            string sql = "INSERT INTO [CRAZY_TAXI].[TL_Roles] (rol_nombre ,rol_activo) VALUES (@Nombre, @Activo);  SELECT scope_identity() AS LastID";
            SqlCommand crearRol = SqlUtils.GetNewCommand(sql);

            SqlParameter paramNombre = new SqlParameter("@Nombre", SqlDbType.VarChar);
            paramNombre.IsNullable = false;
            paramNombre.Value = this.Nombre;

            SqlParameter paramActivo = new SqlParameter("@Activo", SqlDbType.Bit);
            paramActivo.IsNullable = false;
            paramActivo.Value = 1;

            crearRol.Parameters.Add(paramNombre);
            crearRol.Parameters.Add(paramActivo);
            crearRol.Connection = connection;
            crearRol.Transaction = transaction;
            this.Id = Convert.ToInt32(crearRol.ExecuteScalar());
        }

        private void CargarFuncionalidades()
        {
            using (SqlConnection connection = SqlUtils.GetConnection())
            {
                string sql = string.Format("SELECT [fxrfun_codigo] FROM [CRAZY_TAXI].[TL_FuncionalidadesPorRol] WHERE [fxrrol_codigo] = {0}", this.Id);
                SqlCommand getFuncionalidades = SqlUtils.GetNewCommand(sql);
                getFuncionalidades.Connection = connection;
                getFuncionalidades.Connection.Open();
                SqlDataReader reader = getFuncionalidades.ExecuteReader();

                if (reader.HasRows)
                {
                    while (reader.Read())
                    {
                        this.Funcionalidades.Add(reader.GetInt32(0));
                    }
                }

                reader.Close();
            }
        }

        private void CargarDatosRol()
        {
            using (SqlConnection connection = SqlUtils.GetConnection())
            {
                string sql = string.Format("SELECT [rol_nombre], [rol_activo] FROM [CRAZY_TAXI].[TL_Roles] WHERE [rol_codigo] = {0}", this.Id);
                SqlCommand getRol = SqlUtils.GetNewCommand(sql);
                getRol.Connection = connection;
                getRol.Connection.Open();
                SqlDataReader reader = getRol.ExecuteReader();

                if (reader.HasRows)
                {
                    reader.Read();
                    this.Nombre = reader.GetString(0);
                    this.Activo = reader.GetBoolean(1);
                }
                else
                {
                    throw new Exception(string.Format("No existe un rol con código {0}.", this.Id));
                }

                reader.Close();
            }
        }

        private void ModificarFuncionalidades(SqlConnection connection, SqlTransaction transaction)
        {
            string sql = string.Format("DELETE FROM [CRAZY_TAXI].[TL_FuncionalidadesPorRol] WHERE [fxrrol_codigo] = {0}", this.Id);
            SqlCommand eliminarFuncionalidades = SqlUtils.GetNewCommand(sql.ToString());
            eliminarFuncionalidades.Connection = connection;
            eliminarFuncionalidades.Transaction = transaction;
            eliminarFuncionalidades.ExecuteNonQuery();

            this.AgregarFuncionalidades(connection, transaction);
        }

        private void ModificarDatosRol(SqlConnection connection, SqlTransaction transaction)
        {
            string sql = "UPDATE [CRAZY_TAXI].[TL_Roles] SET [rol_nombre] = @Nombre, [rol_activo] = @Activo WHERE [rol_codigo] = @Codigo";
            SqlCommand modificarRol = SqlUtils.GetNewCommand(sql);
            
            SqlParameter paramNombre = new SqlParameter("@Nombre", SqlDbType.VarChar);
            paramNombre.IsNullable = false;
            paramNombre.Value = this.Nombre;

            SqlParameter paramActivo = new SqlParameter("@Activo", SqlDbType.Bit);
            paramActivo.IsNullable = false;
            paramActivo.Value = this.Activo ? 1 : 0;

            SqlParameter paramCodigo = new SqlParameter("@Codigo", SqlDbType.Int);
            paramCodigo.IsNullable = false;
            paramCodigo.Value = this.Id;

            modificarRol.Parameters.Add(paramNombre);
            modificarRol.Parameters.Add(paramActivo);
            modificarRol.Parameters.Add(paramCodigo);
            modificarRol.Connection = connection;
            modificarRol.Transaction = transaction;
            modificarRol.ExecuteNonQuery();
        }
    }
}
